package com.guofs.project.common.utils.tree.base.impl;

import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import com.guofs.project.common.utils.function.BiFunction;
import com.guofs.project.common.utils.tree.base.TreeBase;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author 郭芳诗
 * @date 2019/1/18 14:55
 */
public abstract class AbstractTreeBaseImpl<N, K> implements TreeBase<N, K> {
    private static final long serialVersionUID = 8391188558358908698L;

    /**
     * 直接标明树节点判定方法
     * @param node 用来判定的节点
     * @return true表示是树节点
     */
    protected boolean isRoot(N node) {
        return false;
    }

    /**
     * 依据KEY存储子节点的KEY
     * @return 存储的数据
     */
    protected abstract Map<K, List<K>> getChildMap();

    /**
     * 获取子节点列表
     *
     * @param key 被获取子节点的节点唯一标识
     * @return 子节点列表
     */
    @Override
    public List<N> getChildren(K key) {
        List<N> list = new ArrayList<N>();
        List<K> childrenNode = getChildMap().get(key);
        if (childrenNode == null) {
            return null;
        }
        for (K nodeKey: childrenNode) {
            if (nodeKey == null) {
                throw new NullPointerException("节点数据不能为空。");
            }
            list.add(getNodeByKey(nodeKey));
        }
        return list;
    }

    /**
     * 获取所有节点<h3>无序</h3>
     *
     * @return 所有节点信息
     */
    @Override
    public List<N> findAll() {
        final List<N> list = new ArrayList<N>();
        forEach(new Predicate<N>() {
            @Override
            public boolean apply(N input) {
                list.add(input);
                return true;
            }
        });
        return list;
    }

    /**
     * 查找上一级的树(从树根向下传参)
     *
     * @param start       起始值
     * @param node        查找的节点
     * @param accumulator 转换函数
     * @return 转换的值
     */
    @Override
    public <P> P findParents(P start, N node, BiFunction<P, ? super N, P> accumulator) {
        N nodeTemp = node;
        K parentKey;
        List<N> parents = Lists.newArrayList();
        while (nodeTemp != null && !isRoot(nodeTemp)) {
            parents.add(nodeTemp);
            parentKey = getKey(nodeTemp);
            nodeTemp = getParent(parentKey);
        }
        if (nodeTemp != null) {
            parents.add(nodeTemp);
        }
        int i = parents.size() - 1;
        for (;i >= 0; i--) {
            start = accumulator.apply(start, parents.get(i));
        }
        return start;
    }

    /**
     * 查找上一级的树(从当前节点向树根传参)
     *
     * @param start       起始值
     * @param node        查找的节点
     * @param accumulator 转换函数
     * @return 转换的值
     */
    @Override
    public <P> P findParentsReversal(P start, N node, BiFunction<P, ? super N, P> accumulator) {
        N nodeTemp = node;
        K parentKey;
        while (nodeTemp != null && !isRoot(nodeTemp)) {
            start = accumulator.apply(start, nodeTemp);
            parentKey = getKey(nodeTemp);
            nodeTemp = getParent(parentKey);
        }
        if (nodeTemp != null) {
            start = accumulator.apply(start, nodeTemp);
        }
        return start;
    }
}
